package net.oxygen.upload.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import io.minio.ListPartsResponse;
import io.minio.UploadPartResponse;
import io.minio.messages.Part;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.oxygen.upload.enums.BizCodeEnum;
import net.oxygen.upload.model.MultipartUploadCreate;
import net.oxygen.upload.model.UploadPartCreate;
import net.oxygen.upload.request.CompleteMultipartUploadRequest;
import net.oxygen.upload.request.MultipartUploadCreateRequest;
import net.oxygen.upload.request.UploadPartRequest;
import net.oxygen.upload.response.FileUploadResponse;
import net.oxygen.upload.response.MultipartUploadCreateResponse;
import net.oxygen.upload.service.IFileService;
import net.oxygen.upload.service.IMinioService;
import net.oxygen.upload.util.JsonData;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;

/**
 * <p>
 * 功能：文件操作服务类
 * </p>
 *
 * @author 陈伟伟
 * @since 2023/12/18 16:34
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileServiceImpl implements IFileService {

    private final IMinioService minioService;

    @Value("${minio.bucketName}")
    private String bucketName;

    @Value("${minio.endpoint}")
    private String endpoint;

    @Override
    public JsonData uploadFile(MultipartFile file) {
        if (file == null) {
            return JsonData.result(BizCodeEnum.BAD_REQUEST, "文件不能为空");
        }
        String filePath = minioService.uploadFile(file, bucketName);
        return JsonData.success(getFileUrl(filePath));
    }

    @Override
    public MultipartUploadCreateResponse createMultipartUpload(MultipartUploadCreateRequest request) {
        String extName = FileNameUtil.extName(request.getFileName());
        String fileName = IdUtil.fastSimpleUUID() + "." + extName;
        String path = DateUtil.format(new DateTime(), "yyyy/MM/dd");
        String objectName = path + "/" + fileName;
        Multimap<String, String> headers = HashMultimap.create();
        headers.put("Content-Type", request.getContentType());
        MultipartUploadCreate uploadCreate = MultipartUploadCreate.builder()
                .bucketName(bucketName)
                .objectName(objectName)
                .headers(headers)
                .build();
        String uploadId = minioService.uploadId(uploadCreate).result().uploadId();
        log.info("文件上传id：{}，文件名：{}", uploadId, objectName);
        return MultipartUploadCreateResponse.builder()
                .uploadId(uploadId)
                .fileName(objectName)
                .chunks(request.getChunks())
                .build();
    }

    @Override
    public UploadPartResponse uploadPart(UploadPartRequest request) {
        try (InputStream in = request.getFile().getInputStream()) {
            UploadPartCreate create =  UploadPartCreate.builder()
                    .bucketName(bucketName)
                    .objectName(request.getFileName())
                    .uploadId(request.getUploadId())
                    .partNumber(request.getPartNumber())
                    .data(in)
                    .length(request.getFile().getSize())
                    .build();
            return minioService.uploadPart(create);
        } catch (IOException e) {
            log.error("分片上传文件流处理失败", e);
            return null;
        }
    }

    @Override
    public Part[] listParts(CompleteMultipartUploadRequest request) {
        ListPartsResponse listMultipart = minioService.listMultipartUploads(MultipartUploadCreate.builder()
                .bucketName(bucketName)
                .objectName(request.getFileName())
                .maxParts(request.getChunks() + 10)
                .uploadId(request.getUploadId())
                .partNumberMarker(0)
                .build());
        return listMultipart.result().partList().toArray(new Part[]{});
    }

    @Override
    public FileUploadResponse completeMultipartUpload(CompleteMultipartUploadRequest uploadRequest) {
        Part[] parts = listParts(uploadRequest);
        minioService.completeMultipartUpload(MultipartUploadCreate.builder()
                .bucketName(bucketName)
                .uploadId(uploadRequest.getUploadId())
                .objectName(uploadRequest.getFileName())
                .parts(parts)
                .build());
        return FileUploadResponse.builder()
                .url(getFileUrl(uploadRequest.getFileName()))
                .build();
    }

    private String getFileUrl(String filePath) {
        return endpoint + "/" + bucketName + "/" + filePath;
    }
}
